/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
 
+(function(Z)
{
/**************************************************/
//定义常用的对象，便于压缩文件
/**************************************************/
var hasOwn = Object.prototype.hasOwnProperty,
    trim = String.prototype.trim,
    oString = Object.prototype.toString;

/**************************************************/
//断言相关工具类
/**************************************************/
Z.A = Z.Asserts = 
{
    assertNotEmpty: function(value, message)
    {
        Z.assert(!Z.V.isEmpty(value), "assertNotEmpty", message);
    },
    assertNotEmptyBlank: function(value, message)
    {
        Z.assert(!Z.V.isEmptyBlank(value), "assertNotEmptyBlank", message);
    }
};

/**************************************************/
//对象相关工具类
/**************************************************/
Z.O = Z.Objects = 
{
    isOwn: function(obj, prop)
    {//是否自己的属性
        return hasOwn.call(obj, prop);
    },
    
    isCommon: function(obj, prop)
    {//是否普通的属性（属性名为数字或字符串，属性值不是函数）
        if (!Z.O.isOwn(obj, prop))
        {//不是自己的属性不显示
            return false;
        }
            
        if (!Z.T.isNumber(prop) && !Z.T.isString(prop))
        {//键值不是数字和字符串的不显示
            return false;
        }
        
        if (Z.T.isFunction(obj[prop]))
        {//值是函数的不显示
            return false;
        }
            
        return true;
    },
    
    toString : function(obj)
    {//转为字符串，去掉前面的[object 和后面的]
        if (obj === Z.u){
            return "undefined";
        }else if (obj === null){
            return "null";
        }else{
            return oString.call(obj).slice(8, -1);
        }
    },
    
    toStyleString: function(obj)
    {//转为样式字符串
        var strb = "";
        for (var key in obj)
        {
            if (!this.isCommon(obj, key))
                continue;
            
            var value = obj[key];
            if (Z.T.isNil(value))
                  continue;
            
            strb += key + ":" + value + ";";
        }
    },
    
    toJSONString: function(obj)
    {//转为JSON字符串
        var strb = "{";
        for (var key in obj)
        {
            if (!this.isCommon(obj, key))
                continue;

            var value = obj[key];
            if (Z.T.isNil(value))
            {//空值统一置为null
                value = null;
            }

            strb += Z.Jsons.toKey(key) + ":" + Z.Jsons.toString(value) + ",";
        }
        
        if (strb.length > 1)
            strb = strb.slice(0, -1);
        strb += "}";
        return strb;
    }
};


/**************************************************/
//ID相关工具类
/**************************************************/
Z.Ids = 
{
    HEX_LETTERS: [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70],
    
    /**
     *  通过随机数和当前时间生成唯一编号，格式：
     *  XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
     *  1、1-8位随机数
     *  2、3段4长度的随机数
     *  3、8位长度时间+4位随机数
     */
    uuid: function()
    {
        var uid = new Array(32);
        var index=0, i=0, j=0;
        
        for (i=0;i<8;i++)
        {//前8位为0-F的随机数
            uid[index++] = this.HEX_LETTERS[Math.floor(Math.random() *  16)];
        }
        
        for (i=0;i<3;i++)
        {//三段3*4随机数
            for (j=0;j<4;j++){
                uid[index++] = this.HEX_LETTERS[Math.floor(Math.random() *  16)];
            }
        }
        
        var time = new Date().getTime();
        var timeString = ("0000000" + time.toString(16).toUpperCase()).substr(-8);
        for (i=0;i<8;i++)
        {//最后8位是时间戳，不足前补0
            uid[index++] = timeString.charCodeAt(i);
        }
        
        for (i=0;i<4;i++)
        {//最后4位随机数
            uid[index++] = this.HEX_LETTERS[Math.floor(Math.random() *  16)];
        }
        
        return String.fromCharCode.apply(null, uid);
    }
};

/**************************************************/
//类型相关工具类
/**************************************************/
Z.T = Z.Types = 
{//Boolean Number String Function Array Date RegExp Object

    //三种基本类型
    isBoolean: function(obj)
    {
        return Z.O.toString(obj) === "Boolean";
    },
    isNumber: function(obj)
    {
        return Z.O.toString(obj) === "Number";
    },
    isString: function(obj)
    {
        return Z.O.toString(obj) === "String";
    },
    isPrimitive: function(obj)
    {
        return Z.T.isBoolean(obj) || Z.T.isNumber(obj) || Z.T.isString(obj);
    },
    
    //五种对象类型
    isFunction: function(obj)
    {
        return Z.O.toString(obj) === "Function";
    },
    isArray: function(obj)
    {
        return Z.O.toString(obj) === "Array";
    },
    isDate: function(obj)
    {
        return Z.O.toString(obj) === "Date";
    },
    isRegExp: function(obj)
    {
        return Z.O.toString(obj) === "RegExp";
    },
    isObject: function(obj)
    {
        return Z.O.toString(obj) === "Object";
    },
    isPlainObject: function(obj)
    {
        if (!obj || !Z.T.isObject(obj) || obj.nodeType || Z.T.isWindow(obj)) 
        {//先排除已知的非纯对象
            //1.undefined,null,"",0,NaN等不是纯对象
            //2.类型不是Object的不是纯对象
            //3.已知的DOM nodes和window不是纯对象
            return false;
        }

        if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf"))
        {//如果自己定义了构造函数，且构造函数不是Object，则认为不是一个纯对象
            //1.var o = {key:"value"};o.constructor = function(){};这种情况不是纯对象
            //2.var o = {key:"value"};o.constructor = Function;这种情况不是纯对象
            //3.var o = {key:"value"};o.constructor = Object;这种情况是纯对象，判断这个的条件是Object上有isPrototypeOf属性
            return false;
        }

        //再检查属性，由于自己的属性优先遍历，所以没有属性或最后一个属性是自己的属性，则认为所有属性是自己的属性，即为纯对象
        var key;
        for (key in obj){}

        return key === Z.u || hasOwn.call(obj, key);
    },
    isLikeArray: function(obj)
    {
        if (!obj || !Z.T.isNumber(obj.length)) 
        {//1.先排除null,undefined,0,"",NaN等为false的对象和没有length属性的或length属性值不是数字的,这2种情况不认为是类数组
            return false;
        }
                
        if (Z.T.isFunction(obj) && obj instanceof Z.Query)
        {//2.Z.Query
            return true;
        }
        
        var clazz = Z.O.toString(obj);
        if (clazz === "Array" || clazz === "Arguments" || clazz === "HTMLCollection" || clazz === "NodeList" || obj.callee || obj.item)
        {//3.如果是已知的Z.Query,Array,Arguments,HTMLCollection,NodeList,则直接返回true,在IE8中clazz是object,所以加上属性判断
            return true;
        }
        
        if (Z.T.isString(obj) || Z.T.isFunction(obj) || Z.T.isWindow(obj))
        {//4.排除string、function和window，它们也有length但不能当数组对待
            return false;
        }
        
        //5.最后要求,必须有定义索引值才表示是类数组，这种情况碰到当length=0时，即使是类数组也在实际运行时不当类数组处理
        return obj[0] != Z.u;
    },
    
    //两种空类型
    isNull: function(obj)
    {
        return obj === null;
    },
    isUndefined: function(obj)
    {
        return obj === Z.u;
    },
    isNaN: function(obj)
    {
        return !(obj == obj);
    },
    isInfinity: function(obj)
    {
        return obj === Infinity;
    },
    isNonInfinity: function(obj)
    {
        return obj === -Infinity;
    },
    isNil: function(obj)
    {
        return obj === null || obj === Z.u || !(obj == obj) || obj === Infinity || obj === -Infinity;
    },
    
    //其他特殊类型
    isWindow: function(obj)
    {
        return obj && typeof(obj) === "object" && "setInterval" in obj;
    },
    isNode: function(obj)
    {
        return obj && obj.nodeType;
    },
    isDocument: function(obj)
    {
        return obj && obj.nodeType === 9;
    },
    isElement: function(obj)
    {
        return obj && obj.nodeType && obj.nodeType !== 9;
    },
    isArguments: function(obj)
    {
        return obj && Z.O.toString(obj) === "Arguments" && Z.T.isNumber(obj.length);
    }
};

/**************************************************/
//验证相关工具类
/**************************************************/
Z.V = Z.Validates = 
{
    /*********************************************************************/
    //单字符，支持是否是数字、小数、字母、大写字母、小写字母、字母和数字
    /*********************************************************************/
    isDigit: function(c)
    {//数字
        return c >= 48 && c <= 57;
    },
    isMinus: function(c)
    {//减号
        return c == 45;
    },
    isDot: function(c)
    {//小数点
        return c === 46;
    },
    isColon: function(c)
    {//冒号
        return c == 58;
    },
    isDigitOrMinus: function(c)
    {//数字或减号，如日期表示
        return (c >= 48 && c <= 57) || c === 45;
    },
    isDigitOrDot: function(c)
    {//数字或小数点
        return (c >= 48 && c <= 57) || c === 46;
    },
    isDigitOrColon: function(c)
    {//数字或冒号，如时间表示
        return (c >= 48 && c <= 57) || c === 58;
    },
    isLetter: function(c)
    {//字母大小写
        return (c >= 65 && c <= 90) || (c >= 97 && c <= 122);
    },
    isLetterLowercase: function(c)
    {//小写字母
        return c >= 97 && c <= 122;
    },
    isLetterUppercase: function(c)
    {//大写字母
        return c >= 65 && c <= 90;
    },
    isLetterOrDigit: function(c)
    {
        return isLetter(c) || isDigit(c);
    },
    
    /***************************************************/
    //字符串验证
    /***************************************************/
    isRegexp: function(regexp, s)
    {
        return regexp.test(s);
    },
    isEmpty: function(s)
    {
        if (s == null || s === '')
            return true;
        s += '';
        return s.length < 1
    },
    isNotEmpty: function(s)
    {
        return !Z.V.isEmpty(s);
    },
    isEmptyBlank: function(s)
    {
        if (s == null || s === '')
            return true;
        s += '';
        if (s.length < 1)
            return true;
        for (var i=0;i<s.length;i++)
        {
            if (s.charAt(i) > String.fromCharCode(32))
                return false;
        }
        return true;
    },
    isNotEmptyBlank: function(s)
    {
        return !Z.V.isEmptyBlank(s);
    },
    isNumeric: function(s)
    {
        return Z.R.NUMERIC.test(s);
    },
    isNumericLen: function(s, min, max)
    {
        return Z.R.NUMERIC.test(s) && s.length >= min && s.length <= max;
    },
    isInteger: function(s)
    {
        return Z.R.INTEGER.test(s);
    },
    isIntegerValue: function(s, min, max)
    {
        return Z.R.INTEGER.test(s) && +s >= min && +s <= max;
    },
    isIntegerPositive: function(s)
    {
        return Z.R.INTEGER_P.test(s);
    },
    isFloat: function(s)
    {
        return Z.R.FLOAT.test(s);
    },
    isAmount2R: function(s)
    {
        return Z.R.AMOUNT_2R.test(s);
    },
    isDate: function(s)
    {
        return Z.R.DATE.test(s);
    },
    isTime: function(s)
    {
        return Z.R.TIME.test(s);
    },
    isDateTime: function(s)
    {
        return Z.R.DATE_TIME.test(s);
    },
    isEmail: function(s)
    {
        return Z.R.EMAIL.test(s);
    },
    isMobile: function(s)
    {
        return Z.R.MOBILE.test(s);
    },
    isMobile11: function(s)
    {
        return Z.R.MOBILE_11.test(s);
    },
    isContain: function(strs, separator, s)
    {
        var strArr = Z.AR.toArray(strs, separator);
        return Z.AR.contains(strArr, s);
    },
    /***************************************************/
    //其他验证
    /***************************************************/
    isLeapYear: function(year)
    {//检查是否闰年
        return (year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0));
    },
};

/**************************************************/
//表单工具类
/**************************************************/
Z.FM = Z.Forms = 
{
    formData: function(form)
    {//组装数据
        if (!form || !form.length)
            return null;
            
        var data = "";
        Z.each(form, function(elem)
        {
            if (elem.disabled || !elem.name || !elem.value)
                return;
            data += elem.name + "=" + Z.encode(elem.value) + "&";
        });

        return (data.length > 0)?data.slice(0, -1):null;
    },
    clearForm: function(form)
    {//清空表单
        if (!form){
            return;
        }
        
        form.reset();
        var length = form.elements.length;
        for (var i=0;i<length;i++)
        {
            var elem = form.elements[i];
            if (elem.type == "text" || elem.type == "textarea")
                elem.value = "";
            else if (elem.type == "select-one")
            {
                if (elem.options.length > 0)
                    elem.options[0].selected = true;
            }
        }
    },
    clearSelect: function(elem)
    {//清空选项
        elem.options.length = 0;
    },
    isChecked: function(name, form)
    {//判断是否选中一个checkbox或radio
        if (!name)
        {//没有指定名称，无法获取
            return false;
        }
        
        var elems = form?form[name]:Z.D.names(name);
        if (!elems)
        {//可能form[name]没有属性即undefined
            return false;
        }
        
        if(!Z.T.isNumber(elems.length))
        {//单个，form[name]得到HTMLInputElement，直接判断即可
            return elems.checked;
        }
        else
        {//多个(NodeList,RadioNodeList都有length)，有一个即表示选中
            return Z.each(elems, function(elem)
            {
                if (elem.checked)
                    return true;
            });
        }
    },
    getChecked: function(name, form)
    {//获取单个被选中的值，可以是checkbox和radio
        if (!name)
        {//没有指定名称，无法获取
            Z.alert("[Z.FM.getChecked]第一个参数必传");
            throw "[Z.FM.getChecked]第一个参数必传";
        }
        
        var elems = form?form[name]:Z.D.names(name);
        if (!elems)
        {//可能form[name]没有属性即undefined
            Z.alert("[Z.FM.getChecked]没有找到["+name+"]的对象");
            throw "[Z.FM.getChecked]没有找到["+name+"]的对象";
        }
        
        if(!Z.T.isNumber(elems.length))
        {//单个，form[name]得到HTMLInputElement，直接判断即可
            if (elems.checked){
                return elems.value;
            }else{
                Z.alert("请选择一个选项")
                throw "请选择一个选项";
            }
        }
        else
        {//多个(NodeList,RadioNodeList都有length)，有一个即表示选中，未选中返回null
            for (var i=0;i<elems.length;i++)
            {
                if (elems[i].checked){
                    return elems[i].value;
                }
            }
            Z.alert("请选择一个选项")
            throw "请选择一个选项";
        }
    },
    getCheckeds: function(name, form)
    {
        var value = Z.FM.getCheckBoxValue(name, form);
        if(Z.V.isEmpty(value))
        {
            Z.alert("请至少选择一项");
            throw "请至少选择一项";
        }
        return value;
    },
    getCheckBoxValue: function(name, form)
    {//获取checkbox的值，多个用逗号隔开
    
        var elems = form?form.elements:Z.D.names(name?name:"*");
        var value = "", isFirst = true;
        Z.each(elems, function(elem)
        {
            if (elem.type == "checkbox" && elem.checked)
            {
                if (name && name != elem.name)
                    return;
                   
                if (isFirst){value = elem.value;isFirst = false;}
                else{value += "," + elem.value;}
            }
        });
        return value;
    },
    doSelectCheckBox: function(name, policy, form)
    {//全选,反选和取消，三个参数都可以不传入
        
        //支持布尔型表示未选中全选，选中则取取消，传this.checked即可
        if (Z.T.isBoolean(policy))
            policy = policy?1:2;
        
        //数值型时指定全选，取消和反选
        policy = policy || 0;
        
        var elems = form?form.elements:Z.D.names(name?name:"*");
        Z.each(elems, function(elem)
        {
            if (elem.type != "checkbox")
                return;
            
            if (name && name != elem.name)
                return;
               
            switch(policy)
            {
                case 1:elem.checked = true;break;//全选
                case 2:elem.checked = false;break;//取消
                default:elem.checked = !elem.checked;break;//反选
            } 
        });
        
        //再判断是否有Z.Checkbox
        if (Z.Checkbox)
        {
            var $chkboxs = (form?Z(form):Z(document)).find(".z-checkbox"+(name?"[data-name="+name+"]":""));
            $chkboxs.each(function(elem)
            {
                var $chkbox = Z(elem);
                switch(policy)
                {
                    case 1:$chkbox.addClass("z-active");break;//全选
                    case 2:$chkbox.removeClass("z-active");break;//取消
                    default:$chkbox.toggleClass("z-active");break;//反选
                } 
            });
        }
    },
    doSelectCheckBoxTree: function(name, checked, value, form)
    {//选择树，选中自己时同时选中所有子节点，和父继承节点
    
        var elems = form?form.elements:Z.D.names(name?name:"*");
        Z.each(elems, function(elem)
        {
            if (elem.type != "checkbox")
                return;
                
            if (name && name != elem.name)
                return;
                
            if (elem.value.length > value.length)
            {//如果长度大于当前长度则用取当前值比
                var c_value = elem.value.substring(0, value.length);
                if (c_value == value)
                {//下级
                    if (checked)
                    {//由选中变为不选中,下级变为不选中
                        elem.checked = true;
                    }
                    else
                    {//由未选中变为选中,下级都变选中
                        elem.checked = false;      //check all
                    }
                }
            }
            else if(elem.value.length < value.length)
            {//如果长度小于当前长度则认为可能是上级
                var len = elem.value.length;
                var p_value = value.substring(0, len);
                if (p_value == elem.value)
                {//上级
                    if (checked)
                    {//由未选中变为选中,上级都变选中
                        elem.checked = true;
                    }
                    
                    //由选中变为不选中,上级不变
                }
            }
        });
    }
};

/**************************************************/
//数组相关工具类
/**************************************************/
Z.J = Z.Jsons = 
{
    toObject: function(str)
    {
        if (JSON && JSON.parse)
        {//EMCA5有JSON对象
            return JSON.parse(str);
        }
        else
        {//否则执行语句返回对象
            return Z.evals(str);
        }
    },
    
    toString: function(obj)
    {
        if (JSON && JSON.stringify)
        {//EMCA5有JSON对象
            return JSON.stringify(obj);
        }

        if (Z.T.isNil(obj) || Z.T.isFunction(obj))
        {//JS中的空值和函数都返回null
            return "null";
        }
            
        var type = Z.O.toString(obj);
        switch(type)
        {
            case "String": return "\"" + Z.Jsons.addEscapeChar(obj, "\"") + "\"";
            case "Number": return String(obj);
            case "Boolean": return String(obj);
            case "Date": return Z.DT.toDateTimeString(obj);
            case "RegExp": return Z.Jsons.toString(obj.toString());
            case "Array": return Z.AR.toJSONString(obj);
            default:
            {//对象
                if (Z.T.isLikeArray(obj))
                    return Z.AR.toJSONString(obj);
                else
                    return Z.O.toJSONString(obj);
            }
        }
    },
    
    toKey: function(key)
    {
        return "\"" + (Z.T.isNumber(key)?key:Z.Jsons.addEscapeChar(key, "\"")) + "\"";
    },
    
    addEscapeChar: function(str, quotation)
    {
        var strb = "";
        Z.each(str, function(c)
        {
            switch (c)
            {
            case '\\':strb += "\\\\";return;
            case '\"':if (!quotation || quotation == '\"')strb += "\\\"";return;
            case '\'':if (!quotation || quotation == '\'')strb += "\\\'";return;//双引号下的引单号不转义，用于简单转化字符串
            case '\b':strb += "\\b";return;
            case '\f':strb += "\\f";return;
            case '\r':strb += "\\r";return;
            case '\n':strb += "\\n";return;
            case '\t':strb += "\\t";return;
            case '/':strb += "\\/";return;
            default:strb += c;return;
            }
        });
        return strb;
    }
};

/**************************************************/
//数组相关工具类
/**************************************************/
Z.DT = Z.DateTimes = 
{
    /*************************************************************/
    //获取当前时间格式，包括标准DT,D,T,17,14,12,8,7,6等常用格式
    /*************************************************************/
    
    /**
     * 取得当前的日期时间字符串yyyy-MM-dd HH:mm:ss
     * 
     * @return String 取得当前的日期时间字符串yyyy-MM-dd HH:mm:ss
     */
    getDateTimeString: function()
    {
        var date = new Date();
        return date.getFullYear() + "-" + 
               Z.S.prefixZero(date.getMonth()+1, 2) + "-" + 
               Z.S.prefixZero(date.getDate(), 2) + " " + 
               Z.S.prefixZero(date.getHours(), 2) + ":" + 
               Z.S.prefixZero(date.getMinutes(), 2) + ":" + 
               Z.S.prefixZero(date.getSeconds(), 2);
    },
    
    /**
     * 取得当前的日期时间字符串yyyy-MM-dd
     * 
     * @return String 取得当前的日期时间字符串
     */
    getDateString: function()
    {
        var date = new Date();
        return date.getFullYear() + "-" + 
               Z.S.prefixZero(date.getMonth()+1, 2) + "-" + 
               Z.S.prefixZero(date.getDate(), 2);
    },
    
    /*************************************************************/
    //获取当前时间值，年、月、日期、小时、分钟、秒、星期
    /*************************************************************/
    
    /**
     * 获取当前年份
     * 
     * @return 当前日期
     */
    getCurrentYear: function()
    {
        return new Date().getFullYear();
    },

    /**
     * 获取当前月份
     * 
     * @return 月份
     */
    getCurrentMonth: function()
    {
        return new Date().getMonth() + 1;
    },
    
    /** 获取当前月天数 */
    getCurrentMonthDays: function()
    {
        var date = new Date();
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        return this.getMonthDays(year, month);
    },
    
    /** 获取当前日期 */
    getCurrentDay: function()
    {
        return new Date().getDate();
    },
    
      /********************************************************/
    //相关的日期计算方法
    /********************************************************/
    
    /**
     * 获取指定月天数
     * 
     * @param year 年份
     * @param month 月份
     * @return 2月28/29，1月31
     */
    getMonthDays: function(year, month)
    {
        switch (month)
        {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            return 31;
        case 4:
        case 6:
        case 9:
        case 11:
            return 30;
        default://2月
            return Z.V.isLeapYear(year)?29:28;
        }
    },
    
    /********************************************************/
    //求星期取值
    /********************************************************/
    
    /**
     * 获取指定时间的星期数:星期一=1;星期二=2;星期三=3;星期四=4;星期五=5;星期六=6;星期日=7;
     * 
     * @param year 年份(yyyy)
     * @param month 月份(1-12)
     * @param day 日期(1-31)
     * @return 星期一=1;星期二=2;星期三=3;星期四=4;星期五=5;星期六=6;星期日=7;
     */
    getDateWeek: function(year, month, day)
    {
        var week = new Date(year, month-1, day).getDay();
        return week==0?7:week;
    },
    
    /********************************************************/
    //时间转换，String和Date之间转换
    /********************************************************/
    /**
     * 生成标准日期,格式为 yyyy-MM-dd
     * 
     * @param date The Date
     * @return 生成日期,格式为  yyyy-MM-dd
     */
    toDateString: function(date)
    {
        return date.getFullYear() + "-" + Z.S.prefixZero(date.getMonth() + 1, 2) + "-" + Z.S.prefixZero(date.getDate(), 2);
    },
    
    /**
     * 根据输入的时间,生成时间格式 HH:mm:ss
     * 
     * @param date Date
     * @return 生成时间格式为HH:mm:ss
     */
    toTimeString: function(date)
    {
        return Z.S.prefixZero(date.getHours(), 2) + ":" + Z.S.prefixZero(date.getMinutes(), 2) + ":" + Z.S.prefixZero(date.getSeconds(), 2);
    },
    
    /**
     * 生成标准格式的字符串 格式为: "yyyy-MM-dd HH:mm:ss"
     *
     * @param date The Date
     * @return 生成默认格式的字符串 格式为: "yyyy-MM-dd HH:mm:ss"
     */
    toDateTimeString: function(date)
    {
        return Z.DT.toDateString(date) + " " + Z.DT.toTimeString(date);
    },
    
    /**
     * 字符串转为时间,字符串符合标准日期格式:"yyyy-MM-dd",和标准时间格式:"HH:mm:ss"
     * 
     * @param date 标准日期格式 "yyyy-MM-dd"
     * @param time 标准时间格式 "HH:mm:ss"
     * @return Date
     */
    toDate: function (date, time)
    {
        var datetime;
        if (Z.V.isDateTime(date))
        {//如果第一个参数date是datetime则忽略time
            datetime = date;
        }
        else
        {
            if (!Z.V.isDate(date))
                return null;//如果不是date类型，则第一参数不正确返回null
                
            //有time且正确，则date+time，否则date+00:00:00
            datetime = date + " " + (Z.V.isTime(time)?time:"00:00:00");
        }
        
        var ret = datetime.match(Z.R.DATE_TIME_MATCH);
        return ret?new Date(ret[1], ret[2]-1, ret[3], ret[4], ret[5], ret[6], 0):null;
    }
};

/**************************************************/
//数组相关工具类
/**************************************************/
Z.AR = Z.Arrays = 
{
    first: function(objs)
    {//第一个
        return (!objs || !objs.length || objs.length==0)?null:objs[0];
    },
    last: function(objs)
    {//最后一个
        return (!objs || !objs.length || objs.length==0)?null:objs[objs.length-1];
    },
    indexOf: function(objs, obj)
    {//要求恒等
        if (!objs || !objs.length)
            return -1;
        
        if (objs.indexOf)
            return objs.indexOf(obj);
        
        for (var i=0;i<objs.length;i++){
            if (obj === objs[i]){
                return i;
            }
        }
        return -1;
    },
    contains: function(objs, obj)
    {
        return Z.AR.indexOf(objs, obj) != -1;
    },
    remove: function(objs, obj)
    {
        var ind = Z.AR.indexOf(objs, obj)
        if (ind != -1){        
            objs.splice(ind, 1);
        }
    },
    toArray: function(strs, separator)
    {
        if (!strs || !separator){
            return [];
        }
        
        var strArr = strs.split(separator);
        if (!strArr){
            return [];
        }
        
        var result = [];
        for (var i=0;i<strArr.length;i++)
        {
            var value = Z.S.trim(strArr[i]);
            if (!Z.V.isEmpty(value)){
                result.push(value);
            }
        }
        return result;
    },
    toObject: function(strs, separator)
    {//把width:100px;height:100px这种转成对象{width: "100px", height: "100px"}
        var obj = {};
        var strArr = this.toArray(strs, separator);
        for (var i=0;i<strArr.length;i++)
        {
            var keyValue = strArr[i].split(":");
            if (keyValue.length < 2)
                  continue;
            
            var key = Z.S.trim(keyValue[0]);
            if (key.length == 0)
                continue;
                
            while (key.charAt(key.length-1) == '-')
            {//先去除最后的中杠
                key = key.substring(0, key.length-1);
            }
            
            if (key.length == 0)
                continue;
            
            while(key.indexOf("-") != -1)
            {//把有中杠的转为下一字母大写
                var ind = key.indexOf("-");
                key = key.substring(0, ind) + key.charAt(ind+1).toUpperCase() + key.substring(ind+2);
            }

            obj[key] = keyValue[1];
        }
        return obj;
    },
    toString: function(values, separator)
    {
        if (!values || !values.length)
            return "";
        
        //如果未传入分隔符默认逗号
        separator = separator || ",";
        var strb = "";
        Z.each(values, function(value){
            strb += value + separator;
        });
        if (strb.length > 0)
            strb = strb.slice(0, -separator.length);
        return strb;
    },
    toJSONString: function(values)
    {
        if (!values)
            return "[]";
            
        var strb = "[";
        Z.each(values, function(value){
            strb += Z.Jsons.toString(value) + ",";
        });
        if (strb.length > 1)
            strb = strb.slice(0, -1);
        strb += "]";
        return strb;
    }
};

/**************************************************/
//字符串相关工具类
/**************************************************/
Z.S = Z.Strings = 
{
    trim: trim?function(s){return s==null?"":trim.call(s);}:function(s)
    {
        return s == null?"":s.toString().replace(Z.R.SPACE_LEFT, "").replace(Z.R.SPACE_RIGHT, "");
    },
    
    trimLeft: function(s)
    {
        return s == null?"":s.toString().replace(Z.R.SPACE_LEFT, "");
    },
    
    trimRight: function(s)
    {
        return s == null?"":s.toString().replace(Z.R.SPACE_RIGHT, "");
    },
    
    startWith: function(str, s)
    {    
         if(str == null || s == null || str.length == 0 || s.length == 0 || s.length > str.length)
             return false;
        return new RegExp("^"+s).test(str);
    },

    endWith: function(str, s)
    {    
        if(str == null || s == null || str.length == 0 || s.length == 0 || s.length > str.length)
             return false;
        return new RegExp(s+"$").test(str);
    },

    equalsIgnoreCase: function(s1, s2)
    {
        if (!Z.T.isString(s1) || !Z.T.isString(s2))
            return false;
            
        return s1.toUpperCase() == s2.toUpperCase();
    },
    
    replaceAll: function(s, src, dest, ignoreCase)
    {
        if (!RegExp.prototype.isPrototypeOf(src))
            return s.replace(new RegExp(src, (ignoreCase ? "gi": "g")), dest);
        else
            return s.replace(src, dest);
    },
    
    lengthUnicode: function(s)
    {
        if (s == null || s.length == 0)
            return 0;
            
        var len = 0;
        for (var i=0;i<s.length;i++)
        {
            if (s.charCodeAt(i) > 127)
                len += 2;
            else
                len += 1;
        }
        return len;
    },
    
    lengthUnicode35: function(s)
    {
        if (s == null || s.length == 0)
            return 0;
            
        var len = 0;
        for (var i=0;i<s.length;i++)
        {
            if (s.charCodeAt(i) > 127)
                len += 5;
            else
                len += 3;
        }
        return len;
    },
    
    toString: function(obj)
    {
        if (obj === Z.u){
            return "undefined";
        }else if (obj === null){
            return "";
        }else if (Z.T.isString(obj)){
            return obj;
        }else{
            return obj.toString();
        }
    },

    toUTF8: function(s)
    {
        var bs = [];
        for (var i=0;i<s.length;i++)
        {
            var c = s.charCodeAt(i);
            if (c <= 0x7F)
            {//0-127单字节
                bs.push(c);
            }
            else if (c <= 0x7FF)
            {//128-2047双字节
                bs.push(0xC0 | ((c >> 6) & 0x1F));
                bs.push(0x80 | (c & 0x3F));
            }
            else
            {//2048-65535三字节
                bs.push(0xE0 | ((c >> 12) & 0x0F));
                bs.push(0x80 | ((c >> 6) & 0x3F));
                bs.push(0x80 | (c & 0x3F));
            }
        }
        
        return new Int8Array(bs);
    },
    
    toHexString: function(b)
    {
        var strb = "";
        for (var i=0;i<b.length;i++){
            strb += Z.S.prefixZero((b[i] & 0xFF).toString(16), 2);
        }
        return strb.toUpperCase();
    },
    
    /********************************************************/
    //以下获取字符串的前缀补位方法
    /********************************************************/
    
    /**
     * 前缀补零，得到给定长度的值,补足0
     * 
     * @param str 初始str
     * @param len 给定长度
     * @return String
     */
    prefixZero: function(str, len)
    {
        return Z.S.prefixLen(str, len, '0');
    },
    
    /**
     * 前缀补齐，通过给定初始str,和前置char,得到给定长度的值, 通常用于前补0等
     * 
     * @param str 初始str
     * @param len 给定长度
     * @param prefix 前置char
     * @return String
     */
    prefixLen: function(str, len, prefix)
    {
        if (!prefix) prefix = '0';
        
        var prefixStr = "";
        for (var i=0;i<len;i++)
        {
            prefixStr += prefix;
        }
        
        str = prefixStr + str;
        return str.substring(str.length - len);
    },
    
    prefixNum: function(text)
    {//取前缀数字,如12px得12,如果不是字符串转化为字符串
        if (!text)
            return 0;
            
        if (Z.T.isNumber(text))
            return text;
        
        if (!Z.T.isString(text))
            text = String(text);
        
        if (Z.V.isEmpty(text))
            return 0;
            
        var isNon = "-" == text.charAt(0);
        if (isNon){
            text = text.substring(1);
        }
           
        var str = "";
        Z.each(text, function(c)
        {
            if ((c < '0' || c > '9') && c != '.')
                return true;

            str += c;
        });
        
        if (str.length == 0){
            return 0;
        }
        
        return isNon?-parseFloat(str, 10):parseFloat(str, 10);
    },
    prefixZeroRemove: function(value)
    {//删除整型的前缀0
        while (value.length > 1 && value.charAt(0) == '0' && value.charAt(1) != '.')
        {//去除类似于023之类前缀0，但0.23的0不能被删除
            value = value.substring(1);
        }
        return value;
    },
    removeSecondDot: function(value)
    {//删除小数第二个小数点后面的数据
        var ind = value.indexOf(".");
        if (ind == -1)
            return value;
        var ind2 = value.indexOf(".", ind+1);
        return (ind2 == -1)?value:value.substring(0, ind2);
    },
    removeAmountZero: function(value)
    {//金额抹零
        var ind = value.indexOf(".");
        if (ind == -1)
            return value;
            
        var zero = -1;
        for (var i=value.length-1;i>=ind;i--)
        {
            var c = value.charAt(i);
            if (c != '0' && c != '.')
                break;
            zero = i;
        }
        
        return (zero == -1)?value:value.substring(0, zero);
    }
};

/**************************************************/
//算数相关工具类
/**************************************************/
Z.Maths = 
{
    multiply: function(m, m2)
    {
        if (Z.T.isNumber(m))
            m = m.toString();
        else if (!Z.T.isString(m) || !Z.V.isFloat(m))
            Z.alert("不支持["+m+"]["+m2+"]非数字相乘");
        
        if (Z.T.isNumber(m2))
            m2 = m2.toString();
        else if (!Z.T.isString(m2) || !Z.V.isFloat(m))
            Z.alert("不支持["+m+"]["+m2+"]非数字相乘");
            
        var mInteger, mDecimal, mLen, hasNegative; 
        var ind = m.indexOf(".");
        if (ind == -1)
        {
            mInteger = m;
            mDecimal = "0";
            mLen = 0;
            hasNegative = false;
        }
        else
        {
            mInteger = m.substring(0, ind);
            mDecimal = m.substring(ind+1);
            mLen = mDecimal.length;
            if (mInteger.charAt(0) == '-'){
                hasNegative = true;
            }
        }
        
        var m2Integer, m2Decimal, m2Len, has2Negative; 
        var ind2 = m2.indexOf(".");
        if (ind2 == -1)
        {
            m2Integer = m2;
            m2Decimal = "0";
            m2Len = 0;
            has2Negative = false;
        }
        else
        {
            m2Integer = m2.substring(0, ind2);
            m2Decimal = m2.substring(ind2+1);
            m2Len = m2Decimal.length;
            if (m2Integer.charAt(0) == '-'){
                has2Negative = true;
            }
        }
        
        var i = parseInt(mInteger) * parseInt(m2Integer);
        if (mLen == 0 && m2Len == 0)
            return i;
        
        var v1 = 0, v2 = 0, v3 = 0, l;
        if (mLen != 0)
        {
            v1 = ((hasNegative)?-mDecimal:mDecimal) * m2Integer;
            for (l=0;l<mLen;l++)
                v1 = v1 / 10;
        }

        if (m2Len != 0)
        {
            v2 = ((has2Negative)?-m2Decimal:m2Decimal) * mInteger;
            for (l=0;l<m2Len;l++)
                v2 = v2 / 10;
        }
        
        if (mLen != 0 && m2Len != 0)
        {
            v3 = ((hasNegative)?-mDecimal:mDecimal) * ((has2Negative)?-m2Decimal:m2Decimal);
            for (l=0;l<(mLen+m2Len);l++)
                v3 = v3 / 10;
        }
        //注意整数不要放最前，否则整数和小数相加时，整数转为小数会不准确
        return v3+v2+v1+i;
    }
}

/**************************************************/
//金额相关工具类
/**************************************************/
Z.AM = Z.Amounts = 
{
    /**
     * 金额分，转为字符串元，转化后最大2位小数点，没有的不保留小数点
     * 
     * @param amount 金额分值
     * @return 金额元值
     */
    toYuan: function(amount)
    {
        var s = (+amount / 100).toString();
        var ind = s.indexOf('.');
        return (ind == -1)?s:s.substring(0, ind+3);
    },
    
    /**
     * 金额分，转为字符串元，转化后强制为2位小数点，没有的为.00
     * 
     * @param amount 金额分值
     * @return 金额元值
     */
    toYuanMustRadix: function(amount)
    {
        var s = (+amount / 100).toString();
        var ind = s.indexOf('.'), len = s.length;
        if (ind == -1)//无小数
            return s + ".00";
        else if (ind == len-2)//1位小数
            return s + "0";
        else
            return s.substring(0, ind+3);
    },
    
    /**
     * 金额元字符串转int金额分，支持整数、1位小数和2位小数点的金额字符串
     * 
     * @param str  金额元的字符串
     * @param defaultValue 缺省值
     * @return int 金额分
     */
    toFen: function(str, defaultValue)
    {
        if (Z.T.isNumber(str))
            return Z.Maths.multiply(str, 100);
            
        if (!Z.V.isAmount2R(str))
            return defaultValue || 0;
            
        return Z.Maths.multiply(+str, 100);
    }
};

/**************************************************/
//颜色相关工具类
/**************************************************/
Z.Colors = 
{
    /** 数字的颜色转为字符串#750848十六进制格式 */
    toString: function(iColor)  
    {        
        var sColor = iColor.toString(16);
        return "#" + Z.S.prefixZero(sColor, 6);
    },
    
    /** 字符串十六进制#750848格式转为数字的颜色 */
    toInt: function(sColor)
    {
        if (!sColor || (sColor.length != 4 && sColor.length != 7))
            return 0;
        
        //去掉#
        sColor = sColor.substring(1);
        if (sColor.length == 3)
            sColor = sColor[0] + sColor[0] + sColor[1] + sColor[1] + sColor[2] + sColor[2];
        
        return parseInt(sColor, 16);
    },
    
    /** 颜色转为红绿蓝数组 */
    toArray: function(color)
    {
        if (!Z.T.isString(color) && !Z.T.isNumber(color))
            return [0, 0, 0];
            
        var sColor;
        if (Z.T.isString(color))
            sColor = color;
        else
            sColor = this.toString(color);

        var red = color.substring(1, 3);
        var green = color.substring(3, 5);
        var blue = color.substring(5);
        
        var iRed = parseInt(red, 16);
        var iGreen = parseInt(green, 16);
        var iBlue = parseInt(blue, 16);
        
        return [iRed, iGreen, iBlue];
    }
};

//END
})(zhiqim);